﻿using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using EnvDTE;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Collections.Specialized;

namespace tomenglertde.SetupProject.ViewModel
{
    public class ProjectMapping : INotifyPropertyChanged
    {
        private readonly SetupProjectViewModel _setupProject;
        private readonly EnvDTE.Project _project;

        const string Xmlns = "http://schemas.microsoft.com/developer/msbuild/2003";

        public ProjectMapping(SetupProjectViewModel setupProject, EnvDTE.Project project)
        {
            _setupProject = setupProject;
            _project = project;

            ((INotifyCollectionChanged)_setupProject.ProjectOutputs).CollectionChanged += ProjectOutputs_CollectionChanged;

            Name = _project.Name;
            Guid = GetProjectGuid(_project);
        }

        void ProjectOutputs_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            PropertyChanged(this, new PropertyChangedEventArgs("ProvidesOutput"));
        }

        public string Name
        {
            get;
            private set;
        }

        public string Guid
        {
            get;
            private set;
        }

        public IEnumerable<string> OutputNames
        {
            get
            {
                return _project.ConfigurationManager.ActiveConfiguration.OutputGroups.Cast<EnvDTE.OutputGroup>().Select(g => g.CanonicalName);
            }
        }

        public string BuildOutput
        {
            get
            {
                var group = _project.ConfigurationManager.ActiveConfiguration.OutputGroups.Cast<EnvDTE.OutputGroup>().SingleOrDefault(g => g.CanonicalName == "Built");
                if (group == null)
                    return string.Empty;
                if (group.FileCount == 0)
                    return string.Empty;

                return group.FileNames[0];
            }
        }

        public bool ProvidesOutput
        {
            get
            {
                return _setupProject.ProjectOutputs.Any(p => p.ProjectGuid == Guid);
            }
        }

        public bool? this[string groupName]
        {
            get
            {
                if (!OutputNames.Contains(groupName))
                    return null;

                return _setupProject.ProjectOutputs.Any(p => (p.OutputGroup == groupName) && (p.ProjectGuid == Guid));
            }
            set
            {
                var outputs = _setupProject.ProjectOutputs;

                try
                {

                    if (value.GetValueOrDefault())
                    {
                        if (outputs.Any(p => (p.OutputGroup == groupName) && (p.ProjectGuid == Guid)))
                            return;

                        var template = outputs.FirstOrDefault(p => p.ProjectGuid == Guid) ?? outputs.First();
                        var output = template.Clone();

                        output.OutputGroup = groupName;
                        output.SourcePath = string.Empty;
                        output.ProjectGuid = Guid;
                        output.Id = "_" + System.Guid.NewGuid().ToString("N");

                        _setupProject.ProjectOutputNodes.Add(output.Node);
                    }
                    else
                    {
                        var item = outputs.SingleOrDefault(p => (p.OutputGroup == groupName) && (p.ProjectGuid == Guid));
                        if (item != null)
                        {
                            _setupProject.ProjectOutputNodes.Remove(item.Node);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Trace.Fail(ex.Message);
                }
            }
        }

        private static string GetProjectGuid(Project project)
        {
            try
            {
                var projectFilePath = project.FullName;

                if (string.IsNullOrEmpty(projectFilePath))
                    return string.Empty;

                if (!File.Exists(projectFilePath))
                    return string.Empty;

                var doc = XDocument.Load(projectFilePath);
                return doc.Descendants(XName.Get("ProjectGuid", Xmlns)).Single().Value;
            }
            catch (Exception)
            {
                return string.Empty;
            }
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged = (_, __) => { };

        #endregion
    }
}
